namespace SimpleWebServices.Models
{
    using System;
    using System.Collections.Specialized;
    using System.Web;
    using Moq;
    using SimpleWebServices;
    using SimpleWebServices.Data;
    using SimpleWebServices.Web;
    using SimpleWebServices.Web.UI.Html;
    using Xunit;

    public sealed class TenantFormFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<TenantForm>()
                .DerivesFrom<FormContainer>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("container")
                .Result);
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new TenantForm());
        }

        [Fact]
        public void prop_Results()
        {
            Assert.True(new PropertyExpectations(typeof(TenantForm).GetProperty("Results"))
                .XmlIgnore()
                .IsAutoProperty<FormSubmission>()
                .Result);
        }

        [Fact]
        public void op_Complete_FormSession()
        {
            FakeRepository.Clear();

            try
            {
                Token token = Token.New();

                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant />"
                });
                FakeRepository.Register<TenantForm>(new
                {
                    urn = "urn://example.com/form/abc/xyz",
                    xml = "<container><form /></container>"
                });
                FakeRepository sessions = FakeRepository.Register<FormSession>(new
                {
                    token = token,
                    xml = "<session />"
                });
                FakeRepository submissions = FakeRepository.Register<FormSubmission>();

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample/abc/xyz/form").Verifiable();
                mock.SetupGet<string>(x => x.Request.RawUrl).Returns("/sample/abc/xyz/form?" + token).Verifiable();
                mock.SetupGet<NameValueCollection>(x => x.Request.ServerVariables).Returns(new NameValueCollection()).Verifiable();
                mock.SetupGet<Uri>(x => x.Request.UrlReferrer).Returns(new Uri("http://example.com/")).Verifiable();
                mock.SetupGet<string>(x => x.Request.UserAgent).Returns("Browser Name").Verifiable();
                mock.SetupGet<string>(x => x.Request.UserHostAddress).Returns("127.0.0.1").Verifiable();
                mock.SetupGet<string>(x => x.Server.MachineName).Returns("SERVER01").Verifiable();
                mock.SetupGet<string>(x => x.User.Identity.AuthenticationType).Returns("None").Verifiable();
                mock.SetupGet<bool>(x => x.User.Identity.IsAuthenticated).Returns(false).Verifiable();
                mock.SetupGet<string>(x => x.User.Identity.Name).Returns("Guest").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                TenantForm form = Activator.CreateInstance<TenantForm>().Populated<TenantForm>();
                form.Form.Update(new FormSession());
                form.Token = form.Form.Store(new DataCollection { { "foo", "bar" } });

                form.Complete(SimpleWebServices.Data.Record.Retrieve<FormSession>(form.Token.Value));

                Assert.True(form.Results.Token.HasValue);

                Assert.True((bool)sessions.Xml.CreateNavigator().Evaluate("1=count(/repository/object[@token][@urn]/session/data[@completed='true'])"));

                string xpath = "1=count(/repository/object[@token][@urn='urn://example.com/submission/abc/xyz/" + form.Token.Value + "']/submission";

                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/data[not(@completed)])"));

                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='Request.RawUrl'][@content='/sample/abc/xyz/form?" + token + "'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='Request.UrlReferrer'][@content='http://example.com/'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='Request.UserAgent'][@content='Browser Name'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='Server.MachineName'][@content='SERVER01'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='User.AuthenticationType'][@content='None'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='User.IsAuthenticated'][@content='false'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='User.Name'][@content='Guest'])"));
                Assert.True((bool)submissions.Xml.CreateNavigator().Evaluate(xpath + "/metadata/meta[@name='User.IP'][@content='127.0.0.1'])"));

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }

        [Fact]
        public void op_Complete_FormSessionNull()
        {
            Assert.Throws<ArgumentNullException>(() => new TenantForm().Complete(null as FormSession));
        }

        [Fact]
        public void op_TemplateOfT()
        {
            FakeRepository.Clear();

            try
            {
                FakeRepository.Register<Tenant>(new
                {
                    urn = "urn://example.com/tenant/sample",
                    xml = "<tenant />"
                });
                FakeRepository.Register<TenantForm>(new
                {
                    urn = "urn://example.com/form/abc/xyz",
                    xml = "<container />"
                });

                var mock = new Mock<HttpContextBase>();
                mock.SetupGet<string>(x => x.Request.Path).Returns("/sample/abc/xyz/form").Verifiable();
                HttpContextFactory.Mock = mock.Object;

                Assert.NotNull(new TenantForm().Template<TenantForm>());

                mock.VerifyAll();
            }
            finally
            {
                FakeRepository.Reset();
                HttpContextFactory.Reset();
            }
        }
    }
}